package com.wing.oauth2.exception;

import com.wing.common.utils.JsonResult;
import com.wing.common.utils.Result;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.*;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.exceptions.*;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


/**
 * 统一异常处理
 * RestControllerAdvice 加扫包，要不然有个问题，扫到AuthorizationEndpoint的话，授权码模式和简化模式会有问题
 *
 * @author
 */
@ResponseBody
@Log4j2
public class OAuth2ExceptionHandler implements WebResponseExceptionTranslator<OAuth2Exception> {


    @ExceptionHandler(Exception.class)
    public JsonResult handleException(Exception e) {
        log.error("未知异常:{0}", e);
        return JsonResult.error(JsonResult.Code.SYSTEM_ERROR);
    }

    @ExceptionHandler(AccessDeniedException.class)
    public JsonResult handleAccessDeniedException(Exception e) {
        return JsonResult.error(JsonResult.Code.ACCESS_DENIED);
    }

    @ExceptionHandler(ApiException.class)
    public JsonResult handleApiException(Exception e) {
        log.error("api异常:{0}", e);
        return JsonResult.error(JsonResult.Code.SYSTEM_ERROR);
    }

    @ExceptionHandler(CustomOauthTokenException.class)
    public JsonResult handleCustomOauthTokenException(CustomOauthTokenException e) {
        return JsonResult.error(e.getCode(), e.getMessage());
    }


    @Override
    public ResponseEntity<OAuth2Exception> translate(Exception e) {
        CustomOauthTokenException body = handleOAuth2Exception(e);
        return new ResponseEntity<>(body, HttpStatus.OK);
    }

    /**
     * 认证相关异常处理
     *
     * @param e e
     * @return CustomOauthTokenException
     */
    private CustomOauthTokenException handleOAuth2Exception(Exception e) {
        if (e instanceof BadCredentialsException) {
            return new CustomOauthTokenException(JsonResult.Code.BAD_CREDENTIALS.getCode(), JsonResult.Code.BAD_CREDENTIALS.getDesc());
        }
        if (e instanceof LockedException) {
            return new CustomOauthTokenException(JsonResult.Code.ACCESS_DENIED.getCode(), JsonResult.Code.ACCESS_DENIED.getDesc());
        }
        if (e instanceof AccountExpiredException) {
            return new CustomOauthTokenException(JsonResult.Code.ACCOUNT_EXPIRED.getCode(), JsonResult.Code.ACCOUNT_EXPIRED.getDesc());
        }
        if (e instanceof CredentialsExpiredException) {
            return new CustomOauthTokenException(JsonResult.Code.CREDENTIALS_EXPIRED.getCode(), JsonResult.Code.CREDENTIALS_EXPIRED.getDesc());
        }
        if (e instanceof InvalidGrantException || e instanceof InvalidTokenException) {
            // 刷新token认证时
            String message = e.getMessage();
            if (message != null && message.contains("Invalid refresh token")) {
                return new CustomOauthTokenException(JsonResult.Code.REFRESH_CREDENTIALS_INVALID.getCode(), JsonResult.Code.REFRESH_CREDENTIALS_INVALID.getDesc());
            }
            // 授权码认证时
            if (message != null && message.contains("Invalid authorization code")) {
                return new CustomOauthTokenException(JsonResult.Code.INVALID_REQUEST.getCode(), "授权码无效或已过期");
            }
            // 用户已被禁用
            if (message != null && message.contains("User is disabled")) {
                return new CustomOauthTokenException(JsonResult.Code.ACCOUNT_DISABLED.getCode(), JsonResult.Code.ACCOUNT_DISABLED.getDesc());
            }
            return new CustomOauthTokenException(JsonResult.Code.BAD_CREDENTIALS.getCode(), JsonResult.Code.BAD_CREDENTIALS.getDesc());
        }
        // 无效grant_type
        if (e instanceof UnsupportedGrantTypeException) {
            return new CustomOauthTokenException(JsonResult.Code.INVALID_REQUEST.getCode(), "无效认证类型");
        }
        // 自定义的认证模式可以直接用这个，可参考mobileCodeAuthenticationProvider
        if (e instanceof CustomOauthTokenException) {
            CustomOauthTokenException exception = (CustomOauthTokenException) e;
            return new CustomOauthTokenException(exception.getCode(), exception.getMessage());
        }
        // 范围不正确
        if (e instanceof InvalidScopeException) {
            return new CustomOauthTokenException(JsonResult.Code.INVALID_REQUEST.getCode(), Result.Code.INVALID_SCOPE.getDesc());
        }
        // 用户名或密码错误
        if (e instanceof UsernameNotFoundException){
            return new CustomOauthTokenException(Result.Code.BAD_CREDENTIALS.getCode(), Result.Code.BAD_CREDENTIALS.getDesc());
        }
        if(e instanceof InternalAuthenticationServiceException){
            if(e.getCause() instanceof DisabledException){
                return new CustomOauthTokenException(JsonResult.Code.ACCOUNT_DISABLED.getCode(), JsonResult.Code.ACCOUNT_DISABLED.getDesc());
            }
        }
        log.error("未知认证异常:{0}", e);
        return new CustomOauthTokenException(JsonResult.Code.SYSTEM_ERROR.getCode(), JsonResult.Code.SYSTEM_ERROR.getDesc());
    }
}
